`default_nettype none

module toplevel(

		input	wire [7:0]	hi_in,
		output	wire [1:0]	hi_out,
		inout	wire [15:0]	hi_inout,
		output	wire		i2c_sda,
		output	wire		i2c_scl,
		output	wire		hi_muxsel,

		input	wire 		clk,
		input	wire    	trig      // apd input signal
        
        );

// Opal-Kelly Host Interface - see opalKelly manual
        
    wire			ti_clk;
	wire [30:0]		ok1;
	wire [16:0]		ok2;
	wire [17*1-1:0]	ok2x;
	
	assign i2c_sda = 1'bz;
	assign i2c_scl = 1'bz;
	assign hi_muxsel = 1'b0;
	
	okWireOR # ( .N( 1 ) ) wireOR ( ok2, ok2x );        // N = 1: okBTPipeOut pipe
   
	okHost okHI (   .hi_in( hi_in ),
					.hi_out( hi_out ),
					.hi_inout( hi_inout ),
					.ti_clk( ti_clk ),
					.ok1( ok1 ),
					.ok2( ok2 ) 
	);

// Declarations
   
    // apd logic
	wire		flag;          // apd flag
	reg			set;           // set flag
	reg			clr;           // clear flag
   reg         phase;          // record clk position
	reg			photon;        // record flag
	
	assign flag = set ^ clr; // flag has multiple drivers

    // ram counter overflow
    
	wire		over;           // counter overflow flag
	reg			set_over;
	reg			clr_over;
	
	assign over = set_over ^ clr_over;

    // pipe ports
    
	wire		strobe;         // see opalKelly manual (curr. not in use)
	wire		read;           // pipe wants data

    // fifo ports
    
	wire [15:0]	fifo_out;       // fifo output - data for pipe       
	wire [9:0]	thresh;         // full threshold value (get it from okWireIn threshWire)
	wire		rst_fifo;       // reset
	wire		prog_full;      // full flag (thresh) - ready to send data
	wire		empty;          // empty flag (not in use)
	wire		full;           // totally full flag (not in use)
	wire     wr_en;

    // ram counter ports
    
	wire		rst_ram;        // reset
	wire 		term;           // termination bit triggers overflow
	wire [9:0]  count;          // counter value - time tag
    
// Circuit
 	
	assign wr_en = photon | over;
		
    // apd logic
	always @( posedge trig ) begin       // record incomming signal
            set <= ~clr;                  // => flag = 1
            phase <= clk;                   // remember clk position => double the time resolution
        end
	
	always @( posedge clk ) begin          // process signal:
		if ( flag )                       // if flag and not photon: photon = 1
			begin                          // if flag and     photon: photon = 0, flag = 0
				if ( photon )
					begin
						photon <= 0;
						clr <= set;
					end
				else
					photon <= 1;
			end
	end
	
    // counter overflow logic
	always @( posedge term ) begin               // record counter overflow
		set_over <= ~clr_over;
	end

	
	always @( posedge clk ) begin           // process signal:
		if( over )                          // if over: clear over
			begin
				clr_over <= set_over;
			end
	end
   
    // reset ram and fifo, see opalKelly manual
	okWireIn controlWire (	.ok1( ok1 ),
							.ep_addr( 8'h00 ),
							.ep_dataout( { rst_ram, rst_fifo } )
						);

    // set fifo threshold, see opalKelly manual
	okWireIn threshWire (	.ok1( ok1 ),
							.ep_addr( 8'h01 ),
							.ep_dataout( thresh )
						);

    // data pipe, see opalKelly manual
	okBTPipeOut pipe (  .ok1( ok1 ),
						.ok2( ok2x[ 0*17 +: 17 ] ),
						.ep_addr( 8'ha0 ),
						.ep_datain( fifo_out ),             // get data from fifo
						.ep_read( read ),                   // request data
						.ep_blockstrobe( strobe ),
						.ep_ready( prog_full )              // start pumping when fifo got enough data
					);

    // fifo (16bit, dual clock, block ram), connecting 200MHz-logic with 48MHz-HostInterface, see xilinx core generator manual
	FIFO fifo (	.din( { photon, phase, count } ),                // 
				.prog_full_thresh( thresh ),                        // get threshold value
				.rd_clk( ti_clk ),                                  // HostInterface clock: 48Mhz
				.rd_en( read ),                                     // send data on request (by pipe)
				.rst( rst_fifo ),                                   // reset (= empty)
				.wr_clk( clk ),                                     // Logic clock clk: 200MHz
				.wr_en( wr_en ),                                    // get ready for data (signal by photon, over) 
				.dout( fifo_out ),                                  // data output
				.empty( empty ),
				.full( full ),
				.prog_full( prog_full )                             // ready to send data
			);
	
    // 10bit ram counter (block ram, width 1k, depth (16+2)bit, single port, read only), see xilinx manual
	RAMB16_S18 # (
    
        // set/reset params
		.INIT( 18'h00000 ),             // initial DO value 
		.SRVAL( 18'h00000 ),            // reset DO value
		.WRITE_MODE( "NO_CHANGE" ),     // does not matter, read only
		
        // initial memory values: value(address) = address + 1
		.INIT_00(256'h0010_000f_000e_000d_000c_000b_000a_0009_0008_0007_0006_0005_0004_0003_0002_0001),
		.INIT_01(256'h0020_001f_001e_001d_001c_001b_001a_0019_0018_0017_0016_0015_0014_0013_0012_0011),
		.INIT_02(256'h0030_002f_002e_002d_002c_002b_002a_0029_0028_0027_0026_0025_0024_0023_0022_0021),
		.INIT_03(256'h0040_003f_003e_003d_003c_003b_003a_0039_0038_0037_0036_0035_0034_0033_0032_0031),
		.INIT_04(256'h0050_004f_004e_004d_004c_004b_004a_0049_0048_0047_0046_0045_0044_0043_0042_0041),
		.INIT_05(256'h0060_005f_005e_005d_005c_005b_005a_0059_0058_0057_0056_0055_0054_0053_0052_0051),
		.INIT_06(256'h0070_006f_006e_006d_006c_006b_006a_0069_0068_0067_0066_0065_0064_0063_0062_0061),
		.INIT_07(256'h0080_007f_007e_007d_007c_007b_007a_0079_0078_0077_0076_0075_0074_0073_0072_0071),
		.INIT_08(256'h0090_008f_008e_008d_008c_008b_008a_0089_0088_0087_0086_0085_0084_0083_0082_0081),
		.INIT_09(256'h00a0_009f_009e_009d_009c_009b_009a_0099_0098_0097_0096_0095_0094_0093_0092_0091),
		.INIT_0A(256'h00b0_00af_00ae_00ad_00ac_00ab_00aa_00a9_00a8_00a7_00a6_00a5_00a4_00a3_00a2_00a1),
		.INIT_0B(256'h00c0_00bf_00be_00bd_00bc_00bb_00ba_00b9_00b8_00b7_00b6_00b5_00b4_00b3_00b2_00b1),
		.INIT_0C(256'h00d0_00cf_00ce_00cd_00cc_00cb_00ca_00c9_00c8_00c7_00c6_00c5_00c4_00c3_00c2_00c1),
		.INIT_0D(256'h00e0_00df_00de_00dd_00dc_00db_00da_00d9_00d8_00d7_00d6_00d5_00d4_00d3_00d2_00d1),
		.INIT_0E(256'h00f0_00ef_00ee_00ed_00ec_00eb_00ea_00e9_00e8_00e7_00e6_00e5_00e4_00e3_00e2_00e1),
		.INIT_0F(256'h0100_00ff_00fe_00fd_00fc_00fb_00fa_00f9_00f8_00f7_00f6_00f5_00f4_00f3_00f2_00f1),

		.INIT_10(256'h0110_010f_010e_010d_010c_010b_010a_0109_0108_0107_0106_0105_0104_0103_0102_0101),
		.INIT_11(256'h0120_011f_011e_011d_011c_011b_011a_0119_0118_0117_0116_0115_0114_0113_0112_0111),
		.INIT_12(256'h0130_012f_012e_012d_012c_012b_012a_0129_0128_0127_0126_0125_0124_0123_0122_0121),
		.INIT_13(256'h0140_013f_013e_013d_013c_013b_013a_0139_0138_0137_0136_0135_0134_0133_0132_0131),
		.INIT_14(256'h0150_014f_014e_014d_014c_014b_014a_0149_0148_0147_0146_0145_0144_0143_0142_0141),
		.INIT_15(256'h0160_015f_015e_015d_015c_015b_015a_0159_0158_0157_0156_0155_0154_0153_0152_0151),
		.INIT_16(256'h0170_016f_016e_016d_016c_016b_016a_0169_0168_0167_0166_0165_0164_0163_0162_0161),
		.INIT_17(256'h0180_017f_017e_017d_017c_017b_017a_0179_0178_0177_0176_0175_0174_0173_0172_0171),
		.INIT_18(256'h0190_018f_018e_018d_018c_018b_018a_0189_0188_0187_0186_0185_0184_0183_0182_0181),
		.INIT_19(256'h01a0_019f_019e_019d_019c_019b_019a_0199_0198_0197_0196_0195_0194_0193_0192_0191),
		.INIT_1A(256'h01b0_01af_01ae_01ad_01ac_01ab_01aa_01a9_01a8_01a7_01a6_01a5_01a4_01a3_01a2_01a1),
		.INIT_1B(256'h01c0_01bf_01be_01bd_01bc_01bb_01ba_01b9_01b8_01b7_01b6_01b5_01b4_01b3_01b2_01b1),
		.INIT_1C(256'h01d0_01cf_01ce_01cd_01cc_01cb_01ca_01c9_01c8_01c7_01c6_01c5_01c4_01c3_01c2_01c1),
		.INIT_1D(256'h01e0_01df_01de_01dd_01dc_01db_01da_01d9_01d8_01d7_01d6_01d5_01d4_01d3_01d2_01d1),
		.INIT_1E(256'h01f0_01ef_01ee_01ed_01ec_01eb_01ea_01e9_01e8_01e7_01e6_01e5_01e4_01e3_01e2_01e1),
		.INIT_1F(256'h0200_01ff_01fe_01fd_01fc_01fb_01fa_01f9_01f8_01f7_01f6_01f5_01f4_01f3_01f2_01f1),

		.INIT_20(256'h0210_020f_020e_020d_020c_020b_020a_0209_0208_0207_0206_0205_0204_0203_0202_0201),
		.INIT_21(256'h0220_021f_021e_021d_021c_021b_021a_0219_0218_0217_0216_0215_0214_0213_0212_0211),
		.INIT_22(256'h0230_022f_022e_022d_022c_022b_022a_0229_0228_0227_0226_0225_0224_0223_0222_0221),
		.INIT_23(256'h0240_023f_023e_023d_023c_023b_023a_0239_0238_0237_0236_0235_0234_0233_0232_0231),
		.INIT_24(256'h0250_024f_024e_024d_024c_024b_024a_0249_0248_0247_0246_0245_0244_0243_0242_0241),
		.INIT_25(256'h0260_025f_025e_025d_025c_025b_025a_0259_0258_0257_0256_0255_0254_0253_0252_0251),
		.INIT_26(256'h0270_026f_026e_026d_026c_026b_026a_0269_0268_0267_0266_0265_0264_0263_0262_0261),
		.INIT_27(256'h0280_027f_027e_027d_027c_027b_027a_0279_0278_0277_0276_0275_0274_0273_0272_0271),
		.INIT_28(256'h0290_028f_028e_028d_028c_028b_028a_0289_0288_0287_0286_0285_0284_0283_0282_0281),
		.INIT_29(256'h02a0_029f_029e_029d_029c_029b_029a_0299_0298_0297_0296_0295_0294_0293_0292_0291),
		.INIT_2A(256'h02b0_02af_02ae_02ad_02ac_02ab_02aa_02a9_02a8_02a7_02a6_02a5_02a4_02a3_02a2_02a1),
		.INIT_2B(256'h02c0_02bf_02be_02bd_02bc_02bb_02ba_02b9_02b8_02b7_02b6_02b5_02b4_02b3_02b2_02b1),
		.INIT_2C(256'h02d0_02cf_02ce_02cd_02cc_02cb_02ca_02c9_02c8_02c7_02c6_02c5_02c4_02c3_02c2_02c1),
		.INIT_2D(256'h02e0_02df_02de_02dd_02dc_02db_02da_02d9_02d8_02d7_02d6_02d5_02d4_02d3_02d2_02d1),
		.INIT_2E(256'h02f0_02ef_02ee_02ed_02ec_02eb_02ea_02e9_02e8_02e7_02e6_02e5_02e4_02e3_02e2_02e1),
		.INIT_2F(256'h0300_02ff_02fe_02fd_02fc_02fb_02fa_02f9_02f8_02f7_02f6_02f5_02f4_02f3_02f2_02f1),

		.INIT_30(256'h0310_030f_030e_030d_030c_030b_030a_0309_0308_0307_0306_0305_0304_0303_0302_0301),
		.INIT_31(256'h0320_031f_031e_031d_031c_031b_031a_0319_0318_0317_0316_0315_0314_0313_0312_0311),
		.INIT_32(256'h0330_032f_032e_032d_032c_032b_032a_0329_0328_0327_0326_0325_0324_0323_0322_0321),
		.INIT_33(256'h0340_033f_033e_033d_033c_033b_033a_0339_0338_0337_0336_0335_0334_0333_0332_0331),
		.INIT_34(256'h0350_034f_034e_034d_034c_034b_034a_0349_0348_0347_0346_0345_0344_0343_0342_0341),
		.INIT_35(256'h0360_035f_035e_035d_035c_035b_035a_0359_0358_0357_0356_0355_0354_0353_0352_0351),
		.INIT_36(256'h0370_036f_036e_036d_036c_036b_036a_0369_0368_0367_0366_0365_0364_0363_0362_0361),
		.INIT_37(256'h0380_037f_037e_037d_037c_037b_037a_0379_0378_0377_0376_0375_0374_0373_0372_0371),
		.INIT_38(256'h0390_038f_038e_038d_038c_038b_038a_0389_0388_0387_0386_0385_0384_0383_0382_0381),
		.INIT_39(256'h03a0_039f_039e_039d_039c_039b_039a_0399_0398_0397_0396_0395_0394_0393_0392_0391),
		.INIT_3A(256'h03b0_03af_03ae_03ad_03ac_03ab_03aa_03a9_03a8_03a7_03a6_03a5_03a4_03a3_03a2_03a1),
		.INIT_3B(256'h03c0_03bf_03be_03bd_03bc_03bb_03ba_03b9_03b8_03b7_03b6_03b5_03b4_03b3_03b2_03b1),
		.INIT_3C(256'h03d0_03cf_03ce_03cd_03cc_03cb_03ca_03c9_03c8_03c7_03c6_03c5_03c4_03c3_03c2_03c1),
		.INIT_3D(256'h03e0_03df_03de_03dd_03dc_03db_03da_03d9_03d8_03d7_03d6_03d5_03d4_03d3_03d2_03d1),
		.INIT_3E(256'h03f0_03ef_03ee_03ed_03ec_03eb_03ea_03e9_03e8_03e7_03e6_03e5_03e4_03e3_03e2_03e1),
		.INIT_3F(256'h0000_07ff_03fe_03fd_03fc_03fb_03fa_03f9_03f8_03f7_03f6_03f5_03f4_03f3_03f2_03f1),
        
        // useless initial parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),

		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),

		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),

		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	
	) RAMCounter (	.DI( 0 ),                // data in, read only
					.DIP( 0 ),                  // parity in (not in use)
					.ADDR( count ),             // memory address = count = value(last_address) = last_address + 1
					.EN( 1 ),                   // always read
					.WE( 0 ),                   // never write
					.SSR( rst_ram ),            // reset
					.CLK( clk ),                // logic clk: 200MHz - 200MHz time tags
					.DO( { term, count } ),     // data out: [15:11] not in use, [10] termination bit, [9:0] time tag
					.DOP( )					       // parity out (not in use)
				);
    
endmodule
